package org.zjvis.datascience.common.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import javafx.util.Pair;
import org.zjvis.datascience.common.dto.TaskDTO;
import org.zjvis.datascience.common.dto.TaskInstanceDTO;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @description Task相关帮助类，主要便于修改JSON操作
 * @date 2021-12-08
 */
public class TaskDTOUtil {

    public static void syncInputAndOutputByTaskDTOBySpecificKeys(TaskDTO task, Map<String, String> map) {
        JSONObject taskDataJson = JSONObject.parseObject(task.getDataJson());
        Iterator<Map.Entry<String, String>> entries = map.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<String, String> entry = entries.next();
            Object extractedResult = getValueByKey(entry.getKey(), taskDataJson);
            setValueByKey(extractedResult, entry.getValue(), taskDataJson);
        }
        task.setDataJson(taskDataJson.toJSONString());
    }

    public static void syncInputAndOutputByTaskDTOByParentSpecificKeys(TaskDTO parent, TaskDTO child, Map<String, String> map) {
        JSONObject parentDataJson = JSONObject.parseObject(parent.getDataJson());
        JSONObject childDataJson = JSONObject.parseObject(child.getDataJson());

        Iterator<Map.Entry<String, String>> entries = map.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<String, String> entry = entries.next();
            Object extractedResult = getValueByKey(entry.getKey(), parentDataJson);
            setValueByKey(extractedResult, entry.getValue(), childDataJson);
        }
        child.setDataJson(childDataJson.toJSONString());
    }


    public static Object getValueByKey(String keyStr, TaskDTO task) {
        String[] parts = keyStr.split("\\.");
        Object result = JSONObject.parseObject(task.getDataJson());
        if (parts.length > 1) {
            for (String key : parts) {
                Pair<String, Object> pair = JsonParseUtil.traverse(key, result);
                result = pair.getValue();
            }
        } else {
            result = ((JSONObject) result).get(parts[0]);
        }
        return result;
    }

    public static <T> T getValueByKey(String keyPath, TaskDTO task, Class<T> clazz) {
        String[] parts = keyPath.split("\\.");
        Object result = JSONObject.parseObject(task.getDataJson());
        if (parts.length > 1) {
            for (String key : parts) {
                Pair<String, Object> pair = JsonParseUtil.traverse(key, result);
                result = pair.getValue();
            }
        } else {
            result = ((JSONObject) result).get(parts[0]);
        }
        if (result instanceof JSONObject) {
            return ((JSONObject) result).toJavaObject(clazz);
        } else if (result instanceof JSONArray) {
            return ((JSONArray) result).toJavaObject(clazz);
        }
        return (T) result;
    }

    public static Object getValueByKey(String keyStr, JSONObject dataJson) {
        String[] parts = keyStr.split("\\.");
        Object result = dataJson;
        if (parts.length > 1) {
            for (String key : parts) {
                Pair<String, Object> pair = JsonParseUtil.traverse(key, result);
                result = pair.getValue();
            }
        } else {
            result = ((JSONObject) result).get(parts[0]);
        }
        return result;
    }

    private static void setValueByKey(Object newValue, String assignedKeyStr, JSONObject dataJson) {
        String[] parts = assignedKeyStr.split("\\.");
        Object result = dataJson;
        if (parts.length > 1) {
            for (int i = 0; i < parts.length; i++) {
                String key = parts[i];
                if (i + 1 == parts.length) {
                    ((JSONObject) result).put(key, newValue);
                } else {
                    Pair<String, Object> pair = JsonParseUtil.traverse(key, result);
                    result = pair.getValue();
                }
            }
        } else {
            ((JSONObject) result).put(assignedKeyStr, newValue);
        }

    }

    /**
     * 通过指定更新对应关系，更新taskDTO中的内容
     * <p>
     * 里面的map 意味 在datajson中 用key的内容 更新 对应value的内容
     *
     * @param task
     */
    public static void syncOutputColsByInputCols(TaskDTO task) {
        HashMap<String, String> params = Maps.newHashMap();
        params.put("input[0].tableCols", "output[0].tableCols");
        params.put("input[0].columnTypes", "output[0].columnTypes");
        syncInputAndOutputByTaskDTOBySpecificKeys(task, params);
    }

    public static void syncInputColsByParentOutputCols(TaskDTO parent, TaskDTO child) {
        HashMap<String, String> params = Maps.newHashMap();
        //parent datajson item -> child datajson item
        params.put("output[0].tableCols", "input[0].tableCols");
        params.put("output[0].columnTypes", "input[0].columnTypes");
        syncInputAndOutputByTaskDTOByParentSpecificKeys(parent, child, params);
    }

    /**
     * 用新值 替换 task - datajson 中的 值
     *
     * @param task
     * @param key
     * @param updateValue
     */
    public static void updateJsonWithSpecificKey(TaskDTO task, String key, Object updateValue) {
        updateJsonWithSpecificKey(task, key, updateValue, false);
    }

    /**
     * 替换 或者 增量 更新 task datajson 中的值
     *
     * @param task
     * @param key
     * @param updateValue
     */
    public static void updateJsonWithSpecificKey(TaskDTO task, String key, Object updateValue, Boolean increment) {
        JSONObject taskDataJson = JSONObject.parseObject(task.getDataJson());
        if (increment) {

        } else {
            taskDataJson.put(key, updateValue);
        }
        task.setDataJson(taskDataJson.toJSONString());
    }


    public static void main(String[] args) {
        String json = "{\"isSample\":\"SUCCESS\",\"modelId\":0,\"maxParentNumber\":1,\"autoJoin\":\"yes\",\"forbidden\":false,\"message\":\"以下特征列不含有缺失值： payment_mode,\\tdeliverydistance; 以下特征列不平稳： akeed_order_id\",\"algType\":\"3\",\"parentType\":[2],\"output\":[{\"tableCols\":[\"akeed_order_id\",\"item_count\",\"payment_mode\",\"driver_accepted_time\",\"promo_code\",\"deliverydistance\",\"delivery_time\",\"preparationtime\",\"grand_total\",\"_record_id_\"],\"nodeName\":\"FILTER\",\"totalRow\":135303,\"semantic\":{\"is_favorite\":\"null\",\"created_at\":\"null\",\"promo_code\":\"null\",\"ready_for_pickup_time\":\"null\",\"delivery_time\":\"null\",\"grand_total\":\"null\",\"vendor_rating\":\"null\",\"deliverydistance\":\"null\",\"order_accepted_time\":\"null\",\"item_count\":\"null\",\"payment_mode\":\"null\",\"_record_id_\":\"null\",\"driver_rating\":\"null\",\"cid_x_loc_num_x_vendor\":\"null\",\"location_type\":\"null\",\"picked_up_time\":\"null\",\"vendor_discount_amount\":\"null\",\"delivery_date\":\"null\",\"akeed_order_id\":\"null\",\"promo_code_discount_percentage\":\"null\",\"delivered_time\":\"null\",\"is_rated\":\"null\",\"vendor_id\":\"null\",\"customer_id\":\"null\",\"driver_accepted_time\":\"null\",\"location_number\":\"null\",\"preparationtime\":\"null\"},\"columnTypes\":[\"NUMERIC\",\"NUMERIC\",\"BIGINT\",\"CHARACTER VARYING\",\"CHARACTER VARYING\",\"NUMERIC\",\"DATE\",\"CHARACTER VARYING\",\"NUMERIC\",\"INTEGER\"],\"subType\":0,\"tableName\":\"pipeline.imputation_stat_38818_1637720427591\"}],\"connected\":true,\"input\":[{\"tableCols\":[\"akeed_order_id\",\"item_count\",\"payment_mode\",\"driver_accepted_time\",\"promo_code\",\"deliverydistance\",\"delivery_time\",\"preparationtime\",\"grand_total\",\"_record_id_\"],\"nodeName\":\"FILTER\",\"totalRow\":135303,\"semantic\":{\"is_favorite\":\"null\",\"created_at\":\"null\",\"promo_code\":\"null\",\"ready_for_pickup_time\":\"null\",\"delivery_time\":\"null\",\"grand_total\":\"null\",\"vendor_rating\":\"null\",\"deliverydistance\":\"null\",\"order_accepted_time\":\"null\",\"item_count\":\"null\",\"payment_mode\":\"null\",\"_record_id_\":\"null\",\"driver_rating\":\"null\",\"cid_x_loc_num_x_vendor\":\"null\",\"location_type\":\"null\",\"picked_up_time\":\"null\",\"vendor_discount_amount\":\"null\",\"delivery_date\":\"null\",\"akeed_order_id\":\"null\",\"promo_code_discount_percentage\":\"null\",\"delivered_time\":\"null\",\"is_rated\":\"null\",\"vendor_id\":\"null\",\"customer_id\":\"null\",\"driver_accepted_time\":\"null\",\"location_number\":\"null\",\"preparationtime\":\"null\"},\"columnTypes\":[\"NUMERIC\",\"NUMERIC\",\"BIGINT\",\"CHARACTER VARYING\",\"CHARACTER VARYING\",\"NUMERIC\",\"DATE\",\"CHARACTER VARYING\",\"NUMERIC\",\"INTEGER\"],\"subType\":0,\"tableName\":\"pipeline.view_4269_38514_\"}],\"highlight\":{\"item_count\":[2.42572741194487,2.455399061032864],\"akeed_order_id\":[268618.3653846154]},\"lastTimeStamp\":1637720421461,\"parentTimeStamps\":[1637232208722],\"isSimple\":false,\"position\":{\"col\":5,\"row\":2},\"outputCols\":[],\"lastStatus\":\"SUCCESS\",\"algName\":\"缺失值插补-通用\",\"setParams\":[{\"formItem\":[{\"chineseName\":\"特征列\",\"name\":\"cols\",\"type\":\"checkboxGroup\",\"message\":\"特征列必须为数值型时间序列\",\"props\":{\"options\":[{\"label\":\"akeed_order_id\",\"value\":\"akeed_order_id\"},{\"label\":\"item_count\",\"value\":\"item_count\"},{\"label\":\"payment_mode\",\"value\":\"payment_mode\"},{\"label\":\"deliverydistance\",\"value\":\"deliverydistance\"},{\"label\":\"grand_total\",\"value\":\"grand_total\"}]}},{\"chineseName\":\"插补方法\",\"name\":\"method\",\"type\":\"select\",\"props\":{\"options\":[{\"label\":\"同期插补\",\"value\":\"period_fill\"},{\"label\":\"统计插补\",\"value\":\"stat_fill\"},{\"label\":\"线性插补\",\"value\":\"linear_fill\"}]}},{\"chineseName\":\"时间间隔\",\"name\":\"period\",\"rules\":[{\"trigger\":[\"change\",\"blur\"],\"message\":\"输入值范围为1-12(默认以月为单位）\",\"required\":true}],\"type\":\"inputNumber\",\"message\":\"输入值范围为1-12(默认以月为单位）\",\"props\":{\"min\":1,\"max\":12,\"precision\":0}},{\"chineseName\":\"统计方式\",\"name\":\"stat_method\",\"type\":\"select\",\"props\":{\"options\":[{\"label\":\"全局均数\",\"value\":\"mean_fill\"},{\"label\":\"众数\",\"value\":\"mode_fill\"},{\"label\":\"中位数\",\"value\":\"median_fill\"}]}}],\"condition\":[{\"condition\":[[{\"condition\":\"eq\",\"field\":\"method\",\"value\":\"period_fill\"}]],\"actions\":[{\"type\":\"show\",\"target\":\"period\"},{\"type\":\"hidden\",\"target\":\"stat_method\"}]},{\"condition\":[[{\"condition\":\"eq\",\"field\":\"method\",\"value\":\"stat_fill\"}]],\"actions\":[{\"type\":\"hidden\",\"target\":\"period\"},{\"type\":\"show\",\"target\":\"stat_method\"}]},{\"condition\":[[{\"condition\":\"eq\",\"field\":\"method\",\"value\":\"linear_fill\"}]],\"actions\":[{\"type\":\"hidden\",\"target\":\"period\"},{\"type\":\"hidden\",\"target\":\"stat_method\"}]}],\"intro\":\"通用插补：用非缺失数据的均值或者线性特征对缺失值进行插补。\",\"formData\":{\"period\":1,\"stat_method\":\"mean_fill\",\"method\":\"period_fill\",\"cols\":[\"akeed_order_id\",\"item_count\",\"payment_mode\",\"deliverydistance\"]}}]}";

        JSONObject jsonObject = JSONObject.parseObject(json);
        Object valueByKey = JsonParseUtil.getValueByKey("setParams[0].formItem[0].props.options", jsonObject, List.class);
        System.out.println(valueByKey); //[{"label":"akeed_order_id","value":"akeed_order_id"},{"label":"item_count","value":"item_count"},{"label":"payment_mode","value":"payment_mode"},{"label":"deliverydistance","value":"deliverydistance"},{"label":"grand_total","value":"grand_total"}]

        Object valueByKey2 = JsonParseUtil.getValueByKey("setParams[0].formItem[0].props.options[2]", jsonObject, Map.class);
        System.out.println(valueByKey2); //{"label":"payment_mode","value":"payment_mode"}

    }

    public static void syncOutputByInstance(TaskDTO taskDTO, TaskInstanceDTO instance) {

    }

}

